package com.zenithmind.gateway.config;

import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.util.AntPathMatcher;

import jakarta.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;

/**
 * 网关安全配置类
 * 统一管理所有安全相关的配置和逻辑
 */
@Slf4j
@Data
@Configuration
@EnableWebFluxSecurity
@ConfigurationProperties(prefix = "zenithmind.security")
public class SecurityConfig {
    
    /**
     * 路径匹配器，支持通配符匹配
     */
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    
    /**
     * 是否启用静态安全配置
     */
    private boolean enabled = true;

    /**
     * 公开访问路径列表（不需要认证）
     */
    private List<String> publicPaths = new ArrayList<>();

    /**
     * 受保护路径列表（需要认证）
     */
    private List<String> protectedPaths = new ArrayList<>();
    
    /**
     * 忽略授权验证的URL列表
     */
    private String ignoreUrls = "";
    
    // 默认公开访问的路径列表
    private static final List<String> DEFAULT_PUBLIC_PATHS = Arrays.asList(
        "/api/zenithMind/verification/sendLoginVerificationCode",
        "/api/zenithMind/verification/login",
        "/api/zenithMind/verification/register",
        "/api/zenithMind/verification/resetPassword",
        "/api/zenithMind/auth/token",
        "/actuator/**",
        "/swagger-ui/**",
        "/v3/api-docs/**",
        "/knife4j/**",
        "/favicon.ico"
    );

    @PostConstruct
    public void init() {
        log.info("网关安全配置初始化完成");
        log.info("公开访问路径数量: {}", publicPaths.size() + DEFAULT_PUBLIC_PATHS.size());
        log.info("受保护路径数量: {}", protectedPaths.size());
        
        if (log.isDebugEnabled()) {
            log.debug("默认公开访问路径列表: {}", DEFAULT_PUBLIC_PATHS);
            log.debug("配置的公开访问路径列表: {}", publicPaths);
            log.debug("受保护路径列表: {}", protectedPaths);
            log.debug("忽略URL列表: {}", getIgnoreUrlList());
        }
    }
    
    /**
     * 获取忽略URL列表
     * @return URL列表
     */
    public List<String> getIgnoreUrlList() {
        List<String> result = new ArrayList<>();
        if (ignoreUrls != null && !ignoreUrls.isEmpty()) {
            String[] urls = ignoreUrls.split(",");
            for (String url : urls) {
                if (url != null && !url.trim().isEmpty()) {
                    result.add(url.trim());
                }
            }
        }
        return result;
    }

    /**
     * 判断当前请求路径是否需要跳过权限校验
     *
     * @param path 当前请求的路径
     * @return 如果当前路径是公开的（不需要认证），则返回true；否则返回false
     */
    public boolean shouldSkipAuth(String path) {
        log.trace("检查路径是否需要跳过权限校验: {}", path);

        // 检查默认公开路径列表
        for (String publicPath : DEFAULT_PUBLIC_PATHS) {
            if (publicPath.endsWith("/**")) {
                String prefix = publicPath.substring(0, publicPath.length() - 3);
                if (path.startsWith(prefix)) {
                    log.debug("路径 {} 匹配默认公开路径 {}, 跳过认证。", path, publicPath);
                    return true;
                }
            } else if (path.equals(publicPath)) {
                log.debug("路径 {} 在默认公开路径列表中，跳过认证。", path);
                return true;
            }
        }

        // 检查配置的公开路径列表
        for (String publicPath : publicPaths) {
            if (pathMatcher.match(publicPath, path)) {
                log.debug("路径 {} 匹配公开访问模式 {}, 不需要认证", path, publicPath);
                return true;
            }
        }

        // 检查是否在受保护路径中
        for (String protectedPath : protectedPaths) {
            if (pathMatcher.match(protectedPath, path)) {
                log.debug("路径 {} 匹配受保护模式 {}, 需要认证", path, protectedPath);
                return false;
            }
        }
        
        // 检查忽略的URL列表
        for (String ignoreUrl : getIgnoreUrlList()) {
            if (pathMatcher.match(ignoreUrl, path)) {
                log.debug("路径 {} 在忽略URL列表中，跳过认证", path);
                return true;
            }
        }

        // 默认策略：如果没有明确配置，则需要认证
        log.debug("路径 {} 未匹配任何规则，默认需要认证", path);
        return false;
    }

    /**
     * 判断路径是否需要认证
     * @param path 请求路径
     * @return true表示需要认证，false表示不需要认证
     */
    public boolean needAuthentication(String path) {
        return !shouldSkipAuth(path);
    }

    /**
     * 添加公开访问路径
     * @param path 路径模式
     */
    public void addPublicPath(String path) {
        if (!publicPaths.contains(path)) {
            publicPaths.add(path);
            log.info("添加公开访问路径: {}", path);
        }
    }

    /**
     * 添加受保护路径
     * @param path 路径模式
     */
    public void addProtectedPath(String path) {
        if (!protectedPaths.contains(path)) {
            protectedPaths.add(path);
            log.info("添加受保护路径: {}", path);
        }
    }

    /**
     * 移除公开访问路径
     * @param path 路径模式
     */
    public void removePublicPath(String path) {
        if (publicPaths.remove(path)) {
            log.info("移除公开访问路径: {}", path);
        }
    }

    /**
     * 移除受保护路径
     * @param path 路径模式
     */
    public void removeProtectedPath(String path) {
        if (protectedPaths.remove(path)) {
            log.info("移除受保护路径: {}", path);
        }
    }

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http
            .csrf(ServerHttpSecurity.CsrfSpec::disable)
            .httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
            .formLogin(ServerHttpSecurity.FormLoginSpec::disable)
            .logout(ServerHttpSecurity.LogoutSpec::disable);
        
        http.authorizeExchange(exchanges -> exchanges.anyExchange().permitAll());
            
        return http.build();
    }
} 